#ifndef __PAGE_STREAM_H
#define __PAGE_STREAM_H

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

// ==============================================================
// list defination
// ==============================================================
struct list_head {
  struct list_head *prev, *next;
};

#define list_init(ptr) ((ptr)->prev = (ptr), (ptr)->next = (ptr))

#define list_add(node, head)                           \
  ((node)->prev = (head), (node)->next = (head)->next, \
   (head)->next->prev = (node), (head)->next = (node))

#define list_add_tail(node, head)                      \
  ((node)->prev = (head)->prev, (node)->next = (head), \
   (head)->prev->next = (node), (head)->prev = (node))

#define list_del(entry)                                                      \
  ((entry)->prev->next = (entry)->next, (entry)->next->prev = (entry)->prev, \
   (entry)->prev = (entry)->next = 0)

#define list_del_init(entry) \
  do {                       \
    list_del(entry);         \
    list_init(entry);        \
  } while (0)

#define list_entry(ptr, type, member) \
  ((type *)((char *)(((type *)(ptr))) - offsetof(type, member)))

#define list_is_empty(entry) ((entry) == (entry)->next)

// ===============================================================
// page defination
// ===============================================================
struct page {
  struct list_head head;
  size_t size;
  unsigned char data[2];
};

struct page_stream {
  struct list_head head;
  struct list_head lru;
  size_t lrusize;
  size_t pagesize;
  size_t pos_read;
  size_t pos_write;
  size_t hiwater;
  size_t lowater;
};

extern size_t page_stream_drop(struct page_stream *s, size_t size);
extern size_t page_stream_read(struct page_stream *s, void *ptr, size_t size);
extern size_t page_stream_peek(struct page_stream *s, void *ptr, size_t size);
extern size_t page_stream_write(struct page_stream *s, const void *ptr,
                                size_t size);

#ifdef __cplusplus
}
#endif

#endif
